// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: MIT

package utils

import (
	"crypto/sha256"
	"encoding/hex"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// SecurityUtils 安全工具类
type SecurityUtils struct {
	sensitivePatterns []*regexp.Regexp
	homeDir           string
	workDir           string
}

// NewSecurityUtils 创建安全工具实例
func NewSecurityUtils() *SecurityUtils {
	su := &SecurityUtils{
		sensitivePatterns: []*regexp.Regexp{
			// 匹配常见的敏感路径模式
			regexp.MustCompile(`(?i)/home/[a-zA-Z0-9._-]+/`),      // /home/username/
			regexp.MustCompile(`(?i)/Users/[a-zA-Z0-9._-]+/`),     // macOS /Users/username/
			regexp.MustCompile(`(?i)/root/`),                      // root用户目录
			regexp.MustCompile(`(?i)/etc/[a-zA-Z0-9._-]+/`),       // /etc/下的配置文件
			regexp.MustCompile(`(?i)/var/log/[a-zA-Z0-9._-]+/`),   // 日志文件路径
			regexp.MustCompile(`(?i)/tmp/[a-zA-Z0-9._-]+/`),       // 临时文件路径
			regexp.MustCompile(`(?i)/opt/[a-zA-Z0-9._-]+/`),       // /opt/下的应用目录
			regexp.MustCompile(`(?i)/usr/local/[a-zA-Z0-9._-]+/`), // /usr/local/下的目录
			regexp.MustCompile(`(?i)/srv/[a-zA-Z0-9._-]+/`),       // /srv/下的服务目录
			regexp.MustCompile(`(?i)/mnt/[a-zA-Z0-9._-]+/`),       // 挂载点目录
			regexp.MustCompile(`(?i)/media/[a-zA-Z0-9._-]+/`),     // 媒体目录
			regexp.MustCompile(`(?i)/run/[a-zA-Z0-9._-]+/`),       // /run/下的运行时目录
			regexp.MustCompile(`(?i)/proc/[a-zA-Z0-9._-]+/`),      // /proc/下的进程信息
			regexp.MustCompile(`(?i)/sys/[a-zA-Z0-9._-]+/`),       // /sys/下的系统信息
		},
	}

	// 获取当前用户家目录
	if home, err := os.UserHomeDir(); err == nil {
		su.homeDir = home
	}

	// 获取当前工作目录
	if wd, err := os.Getwd(); err == nil {
		su.workDir = wd
	}

	return su
}

// SanitizePath 清理路径中的敏感信息
func (su *SecurityUtils) SanitizePath(path string) string {
	if path == "" {
		return ""
	}

	// 首先处理家目录路径
	if su.homeDir != "" && strings.HasPrefix(path, su.homeDir) {
		relativePath := strings.TrimPrefix(path, su.homeDir)
		if relativePath == "" || relativePath == "/" {
			return "~"
		}
		return "~" + relativePath
	}

	// 处理工作目录路径
	if su.workDir != "" && strings.HasPrefix(path, su.workDir) {
		relativePath := strings.TrimPrefix(path, su.workDir)
		if relativePath == "" || relativePath == "/" {
			return "."
		}
		return "." + relativePath
	}

	// 使用正则表达式清理敏感路径
	sanitized := path
	for _, pattern := range su.sensitivePatterns {
		if pattern.MatchString(sanitized) {
			// 匹配到敏感路径，替换为[REDACTED]/并保留剩余部分
			sanitized = pattern.ReplaceAllString(sanitized, "[REDACTED]/")
			break // 只替换第一个匹配的敏感路径
		}
	}

	// 如果路径被完全清理，只保留文件名
	if sanitized != path && !strings.Contains(sanitized, "/") {
		sanitized = filepath.Base(path)
	}

	return sanitized
}

// SanitizeErrorMessage 清理错误消息中的敏感信息
func (su *SecurityUtils) SanitizeErrorMessage(message string) string {
	if message == "" {
		return ""
	}

	// 定义敏感关键词模式
	sensitivePatterns := []string{
		`(?i)password\s*[:=]\s*\S+`,        // password: xxx
		`(?i)passwd\s*[:=]\s*\S+`,          // passwd: xxx
		`(?i)pwd\s*[:=]\s*\S+`,             // pwd: xxx
		`(?i)token\s*[:=]\s*\S+`,           // token: xxx
		`(?i)secret\s*[:=]\s*\S+`,          // secret: xxx
		`(?i)api[_-]?key\s*[:=]\s*\S+`,     // api_key: xxx
		`(?i)access[_-]?key\s*[:=]\s*\S+`,  // access_key: xxx
		`(?i)private[_-]?key\s*[:=]\s*\S+`, // private_key: xxx
		`(?i)auth\s*[:=]\s*\S+`,            // auth: xxx
		`(?i)bearer\s+\S+`,                 // Bearer token
		`(?i)basic\s+\S+`,                  // Basic auth
		`mongodb://\S+:\S+@`,               // MongoDB URI with credentials
		`mysql://\S+:\S+@`,                 // MySQL URI with credentials
		`postgres://\S+:\S+@`,              // PostgreSQL URI with credentials
		`redis://\S+:\S+@`,                 // Redis URI with credentials
	}

	sanitized := message
	for _, pattern := range sensitivePatterns {
		re := regexp.MustCompile(pattern)
		sanitized = re.ReplaceAllString(sanitized, "[REDACTED]")
	}

	// 清理路径信息
	sanitized = su.SanitizePath(sanitized)

	return sanitized
}

// SanitizeStackTrace 清理堆栈跟踪中的敏感信息
func (su *SecurityUtils) SanitizeStackTrace(stackTrace string) string {
	if stackTrace == "" {
		return ""
	}

	lines := strings.Split(stackTrace, "\n")
	for i, line := range lines {
		// 清理包含文件路径的行
		if strings.Contains(line, ".go:") || strings.Contains(line, ".py:") || strings.Contains(line, ".js:") {
			// 使用正则表达式匹配文件路径
			pathRegex := regexp.MustCompile(`([^\s]+[/\\][^\s]+\.(?:go|py|js)):(\d+)`)
			lines[i] = pathRegex.ReplaceAllStringFunc(line, func(match string) string {
				parts := strings.Split(match, ":")
				if len(parts) >= 2 {
					filePath := parts[0]
					lineNum := parts[1]

					// 如果是Go标准库路径，保持不变
					if strings.Contains(filePath, "/go/src/") || strings.Contains(filePath, "/usr/local/go/") {
						return match
					}

					// 清理路径
					cleanPath := su.SanitizePath(filePath)
					return cleanPath + ":" + lineNum
				}
				return match
			})
		}
	}

	return strings.Join(lines, "\n")
}

// MaskEmail 屏蔽邮箱地址
func (su *SecurityUtils) MaskEmail(email string) string {
	if email == "" || !strings.Contains(email, "@") {
		return email
	}

	parts := strings.Split(email, "@")
	if len(parts) != 2 {
		return email
	}

	username := parts[0]
	domain := parts[1]

	// 屏蔽用户名部分
	if len(username) <= 3 {
		return "***@" + domain
	}

	// 保留第一个和最后一个字符，中间用*填充
	maskedUsername := username[:1] + strings.Repeat("*", len(username)-2) + username[len(username)-1:]
	return maskedUsername + "@" + domain
}

// MaskIP 屏蔽IP地址
func (su *SecurityUtils) MaskIP(ip string) string {
	if ip == "" {
		return ""
	}

	// 检查是否为IPv4
	if strings.Contains(ip, ".") {
		parts := strings.Split(ip, ".")
		if len(parts) == 4 {
			// 只显示最后一段
			return "*.*.*." + parts[3]
		}
	}

	// 检查是否为IPv6
	if strings.Contains(ip, ":") {
		parts := strings.Split(ip, ":")
		if len(parts) > 2 {
			// 只显示最后一段
			return "*:*:" + parts[len(parts)-1]
		}
	}

	return ip
}

// HashSensitiveData 对敏感数据进行哈希处理
func (su *SecurityUtils) HashSensitiveData(data string) string {
	if data == "" {
		return ""
	}

	// 使用SHA-256哈希
	hash := sha256.Sum256([]byte(data))
	// 返回完整的32字节哈希的十六进制表示（64个字符）
	return hex.EncodeToString(hash[:])
}

// IsSensitivePath 判断是否为敏感路径
func (su *SecurityUtils) IsSensitivePath(path string) bool {
	if path == "" {
		return false
	}

	// 检查是否在敏感路径前缀列表中
	for _, pattern := range su.sensitivePatterns {
		if pattern.MatchString(path) {
			return true
		}
	}

	return false
}

// ExtractFilename 安全地提取文件名
func (su *SecurityUtils) ExtractFilename(path string) string {
	if path == "" {
		return ""
	}

	// 使用filepath.Base提取文件名
	filename := filepath.Base(path)

	// 如果提取后仍然是路径（特殊情况），进一步清理
	if strings.Contains(filename, "/") || strings.Contains(filename, "\\") {
		// 递归提取直到得到纯文件名
		parts := strings.Split(filename, "/")
		if len(parts) > 0 {
			filename = parts[len(parts)-1]
		}
	}

	return filename
}

// 全局安全工具实例
var globalSecurityUtils = NewSecurityUtils()

// SanitizePath 使用全局实例清理路径
func SanitizePath(path string) string {
	return globalSecurityUtils.SanitizePath(path)
}

// SanitizeErrorMessage 使用全局实例清理错误消息
func SanitizeErrorMessage(message string) string {
	return globalSecurityUtils.SanitizeErrorMessage(message)
}

// SanitizeStackTrace 使用全局实例清理堆栈跟踪
func SanitizeStackTrace(stackTrace string) string {
	return globalSecurityUtils.SanitizeStackTrace(stackTrace)
}

// HashSensitiveData 使用全局实例哈希敏感数据
func HashSensitiveData(data string) string {
	return globalSecurityUtils.HashSensitiveData(data)
}

// MaskEmail 使用全局实例屏蔽邮箱
func MaskEmail(email string) string {
	return globalSecurityUtils.MaskEmail(email)
}

// MaskIP 使用全局实例屏蔽IP地址
func MaskIP(ip string) string {
	return globalSecurityUtils.MaskIP(ip)
}

// IsSensitivePath 使用全局实例判断敏感路径
func IsSensitivePath(path string) bool {
	return globalSecurityUtils.IsSensitivePath(path)
}

// ExtractFilename 使用全局实例安全提取文件名
func ExtractFilename(path string) string {
	return globalSecurityUtils.ExtractFilename(path)
}
